/*************************************************************************
 *  Copyright © 2023-2030 FXB CO.,LTD. All rights reserved.
 *------------------------------------------------------------------------
 *  公司：DefaultCompany
 *  项目：UPMProject
 *  文件：PackageInfoProcess.cs
 *  作者：Administrator
 *  日期：2024/12/26 16:33:57
 *  功能：Nothing
*************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
using System.Threading.Tasks;
using System.Threading;
using SVNPackageManager.Runtime;

namespace SVNPackageManager.Editor
{
    [System.Serializable]
    public class PackageDataProcessor
    {
        public List<PackageSourceInfo> packageSourceListInfos = new List<PackageSourceInfo>();
        public List<PackageGroupInfo> packageGroupListInfos = new List<PackageGroupInfo>();

        public string curSelectedGroupID;
        public int curSelectedGroupIndex;
        public string curSelectedPackageID;

        public SVNHelper svnHelper;
        public PackageListCache packageListCache;
        public ScopedRegistryConfig svnScopedRegistryConfig;

        public PackageDataProcessor(SVNHelper svnHelper, PackageResourceManage resourceManage)
        {
            this.svnHelper = svnHelper;
            svnScopedRegistryConfig = resourceManage.svnScopedRegistryConfig;
            packageListCache = resourceManage.packageListCache;
        }

        /// <summary>
        /// 刷新包列表信息
        /// </summary>
        /// <param name="formCache">是否能从内存中拿去</param>
        /// <param name="ct"></param>
        /// <returns></returns>
        public async Task RefreshPackageList(bool fromCache, CancellationToken ct = default)
        {
            packageSourceListInfos.Clear();
            packageGroupListInfos.Clear();

            List<RegistryAddress> registrieAddress = svnScopedRegistryConfig.registrieAddress;

            for (int i = 0; i < registrieAddress.Count; i++)
            {
                List<PackageItemInfo> packageItemListInfos = new List<PackageItemInfo>();
                if (!fromCache || packageListCache.packageConfigs == null)
                {
                    var packageUrls = await GetPackageList(svnHelper, registrieAddress[i]);

                    packageListCache.AddPackageUrlsToCache(registrieAddress[i].Name, packageUrls);

                    packageItemListInfos = await GetPackageInfos(svnHelper, packageUrls);
                }
                else
                {
                    var packageUrls = packageListCache.GetPackageUrlsFromCache(registrieAddress[i].Name);
                    if (packageUrls == null || packageUrls.Count <= 0)
                    {
                        continue;
                    }
                    packageItemListInfos = packageListCache.packageConfigs
                                   .Where(info => packageUrls.Contains(info.packageSvnUrl))
                                   .ToList();
                }

                var packageGroupInfo = PackageGrouping(packageItemListInfos);

                PackageSourceInfo packageSource = new PackageSourceInfo()
                {
                    packageSourceName = registrieAddress[i].Name,
                    packageGroupInfos = packageGroupInfo,
                    packageSourceFolderState = true
                };

                AddpackageGroupListInfos(packageGroupInfo);

                packageSourceListInfos.Add(packageSource);
            }

            packageListCache.SavePackageListCache();
        }

        private void AddpackageGroupListInfos(List<PackageGroupInfo> packageGroupInfo)
        {
            for (int i = 0; i < packageGroupInfo.Count; i++)
            {
                packageGroupInfo[i].groupIndex = packageGroupListInfos.Count((item) => item.packageGroupID == packageGroupInfo[i].packageGroupID);
                packageGroupListInfos.Add(packageGroupInfo[i]);
            }
        }

        private async Task<List<string>> GetPackageList(SVNHelper svnHelper, RegistryAddress registry)
        {
            List<string> packageUrls = await svnHelper.GetSVNListAsync(registry.URL);
            return packageUrls;
        }

        private async Task<List<PackageItemInfo>> GetPackageInfos(SVNHelper svnHelper, List<string> packageUrls, CancellationToken ct = default)
        {
            List<PackageItemInfo> packageItemListInfos = new List<PackageItemInfo>();
            List<PackageItemInfo> checkInstallList = new List<PackageItemInfo>();

            var tasks = new List<Task>();
            using (var semaphore = new SemaphoreSlim(16))
            {
                foreach (var url in packageUrls)
                {
                    await semaphore.WaitAsync(ct);
                    tasks.Add(Task.Run(async () =>
                    {
                        try
                        {
                            if (packageListCache.IsExist(url, out PackageItemInfo itemInfo))
                            {
                                lock (packageItemListInfos)
                                {
                                    packageItemListInfos.Add(itemInfo);
                                }
                            }
                            else
                            {
                                PackageConfig packageConfig = await svnHelper.GetSVNJsonFileContentAsync<PackageConfig>(url);
                                lock (packageItemListInfos)
                                {
                                    PackageItemInfo packageInfo = new PackageItemInfo()
                                    {
                                        packageItemID = $"{packageConfig.name}{packageConfig.version}",
                                        packageSvnUrl = $"{url}",
                                        packageConfig = packageConfig
                                    };

                                    packageItemListInfos.Add(packageInfo);
                                    packageListCache.AddPackageItemToCache(packageInfo);
                                    checkInstallList.Add(packageInfo);
                                }
                            }
                        }
                        finally
                        {
                            semaphore.Release();
                        }
                    }, ct));
                }
                await Task.WhenAll(tasks);

                for (int i = 0; i < checkInstallList.Count; i++)
                {
                    await CheckPackageInstall(checkInstallList[i]);
                }

                return packageItemListInfos;
            }
        }

        private List<PackageGroupInfo> PackageGrouping(List<PackageItemInfo> packageItemListInfos)
        {
            //根据包进行分类，同一类包放在一起
            IEnumerable<IGrouping<string, PackageItemInfo>> packageGroup = packageItemListInfos.GroupBy(item => item.packageConfig.name);

            List<PackageGroupInfo> packageGroupInfos = new List<PackageGroupInfo>();

            foreach (var group in packageGroup)
            {
                List<PackageItemInfo> packages = group.ToList();
                PackageGroupInfo packageGroupInfo = new PackageGroupInfo()
                {
                    packageGroupID = group.Key,
                    packageInfos = packages,
                    installedPackageID = packages.FirstOrDefault(item => item.isInstalled)?.packageItemID,
                };
                packages.ForEach(item =>
                {
                    item.packageGroupID = packageGroupInfo.packageGroupID;
                });

                PackageVeresionSort(packageGroupInfo.packageInfos);
                CheckLatestPackage(packageGroupInfo);

                packageGroupInfos.Add(packageGroupInfo);
            }

            packageGroupInfos = packageGroupInfos.OrderBy((item) => GetOrderContent(item)).ToList();

            return packageGroupInfos;
        }

        private string GetOrderContent(PackageGroupInfo groupInfo)
        {
            string orderContent = groupInfo.packageInfos[0].packageConfig.displayName;
            if (!string.IsNullOrEmpty(orderContent))
            {
                return orderContent;
            }
            return groupInfo.packageInfos[0].packageConfig.name;
        }

        private async Task CheckPackageInstall(PackageItemInfo packageItem)
        {
            PackageConfig config = packageItem.packageConfig;

            PackageInfo packageInfo = await PackageInstaller.IsPackageInstalled(config.name, config.version);

            if (packageInfo != null)
            {
                packageItem.isInstalled = true;
                packageItem.resolvedPath = packageInfo.resolvedPath;
            }
            else
            {
                packageItem.isInstalled = false;
                packageItem.resolvedPath = "";
            }
        }

        private void CheckLatestPackage(PackageGroupInfo packageGroupInfo)
        {
            List<PackageItemInfo> packageInfos = packageGroupInfo.packageInfos;
            if (packageInfos == null || packageInfos.Count <= 0) return;

            Version maxVersion = new Version(packageInfos[0].packageConfig.version);

            PackageItemInfo maxVersionPackage = packageInfos[0];

            for (int i = 0; i < packageInfos.Count; i++)
            {
                packageInfos[i].isLast = false;
                Version version = new Version(packageInfos[i].packageConfig.version);
                if (version > maxVersion)
                {
                    maxVersion = version;
                    maxVersionPackage = packageInfos[i];
                }
            }

            maxVersionPackage.isLast = true;
            packageGroupInfo.lastPackageID = maxVersionPackage.packageItemID;
        }

        private void PackageVeresionSort(List<PackageItemInfo> packageInfos)
        {
            packageInfos.Sort(new PackageComparer());
        }

        public class PackageComparer : IComparer<PackageItemInfo>
        {
            public int Compare(PackageItemInfo x, PackageItemInfo y)
            {
                return new Version(y.packageConfig.version).CompareTo(new Version(x.packageConfig.version));
            }
        }

        /// <summary>
        /// 获取所有的包源信息列表
        /// </summary>
        /// <returns></returns>
        public List<PackageSourceInfo> GetPackageSourceInfos()
        {
            return packageSourceListInfos;
        }

        public List<PackageGroupInfo> GetPackageGroupInfos()
        {
            return packageGroupListInfos;
        }

        /// <summary>
        /// 获取包组信息
        /// </summary>
        /// <param name="packageGroupID"></param>
        /// <returns></returns>
        public PackageGroupInfo GetPackageGroupInfoByIndex(string packageGroupID, int groupIndex)
        {
            if (string.IsNullOrEmpty(packageGroupID)) return null;
            return packageGroupListInfos.FirstOrDefault(item =>
            item.packageGroupID == packageGroupID
            && item.groupIndex == groupIndex);
        }

        /// <summary>
        /// 可能存在多个同名的组
        /// </summary>
        /// <param name="packageGroupID"></param>
        /// <returns></returns>
        public List<PackageGroupInfo> GetPackageGroupInfos(string packageGroupID)
        {
            if (string.IsNullOrEmpty(packageGroupID)) return null;
            return packageGroupListInfos.Where(item =>
            item.packageGroupID == packageGroupID).ToList();
        }

        /// <summary>
        /// 获取包组中的包信息
        /// </summary>
        /// <param name="packageGroupID"></param>
        /// <param name="packageItemID"></param>
        /// <returns></returns>
        public PackageItemInfo GetPackageItemInfoByIndex(string packageGroupID, string packageItemID, int groupIndex)
        {
            if (string.IsNullOrEmpty(packageGroupID) || string.IsNullOrEmpty(packageItemID)) return null;
            PackageGroupInfo groupInfo = GetPackageGroupInfoByIndex(packageGroupID, groupIndex);
            if (groupInfo == null) return null;
            return groupInfo.GetPackageItemInfo(packageItemID);
        }

        public List<PackageItemInfo> GetPackageItemInfos(string packageGroupID, string packageItemID)
        {
            if (string.IsNullOrEmpty(packageGroupID) || string.IsNullOrEmpty(packageItemID)) return null;
            List<PackageGroupInfo> groupInfo = GetPackageGroupInfos(packageGroupID);
            if (groupInfo == null) return null;
            List<PackageItemInfo> itemInfos = new List<PackageItemInfo>();
            for (int i = 0; i < groupInfo.Count; i++)
            {
                PackageItemInfo itemInfo = groupInfo[i].GetPackageItemInfo(packageItemID);
                itemInfos.Add(itemInfo);
            }
            return itemInfos;
        }

        /// <summary>
        /// 获取当前选中的包组信息
        /// </summary>
        /// <returns></returns>
        public PackageGroupInfo GetCurPackageGroupByIndex()
        {
            return GetPackageGroupInfoByIndex(curSelectedGroupID, curSelectedGroupIndex);
        }

        public List<PackageGroupInfo> GetCurPackageGroups()
        {
            return GetPackageGroupInfos(curSelectedGroupID);
        }

        /// <summary>
        /// 获取当前选中的包信息
        /// </summary>
        /// <returns></returns>
        public PackageItemInfo GetCurSelectedPackageByIndex()
        {
            return GetPackageItemInfoByIndex(curSelectedGroupID, curSelectedPackageID, curSelectedGroupIndex);
        }

        public List<PackageItemInfo> GetCurSelectedPackages()
        {
            return GetPackageItemInfos(curSelectedGroupID, curSelectedPackageID);
        }

        /// <summary>
        /// 更新当前选中的包的安装状态和路径
        /// 这里要注意的是，如果是升级的话，那么之前的版本是会卸载掉的
        /// </summary>
        /// <param name="installPath"></param>
        /// <param name="state"></param>
        public void UpdateCurSelectPackageInstallState(string installPath)
        {
            List<PackageGroupInfo> groupInfos = GetCurPackageGroups();
            foreach (var groupInfo in groupInfos)
            {
                foreach (var item in groupInfo.packageInfos)
                {
                    item.resolvedPath = "";
                    item.isInstalled = false;
                    packageListCache.UpdatePackageState(item.packageItemID, false);
                }

                PackageItemInfo packageItem = groupInfo.GetPackageItemInfo(curSelectedPackageID);
                if (packageItem != null)
                {
                    packageItem.resolvedPath = installPath;
                    packageItem.isInstalled = true;
                    packageListCache.UpdatePackageState(packageItem.packageItemID, true);
                }
            }
        }

        /// <summary>
        /// 更新当前选中的包的移除状态和路径
        /// </summary>
        /// <param name="installPath"></param>
        public void UpdateCurSelectPackageRemoveState()
        {
            List<PackageGroupInfo> groupInfos = GetCurPackageGroups();
            foreach (var groupInfo in groupInfos)
            {
                PackageItemInfo packageItem = groupInfo.GetPackageItemInfo(curSelectedPackageID);
                if (packageItem != null)
                {
                    packageItem.resolvedPath = "";
                    packageItem.isInstalled = false;
                    packageListCache.UpdatePackageState(packageItem.packageItemID, false);
                }
            }
        }

        /// <summary>
        /// 获取包组中安装的包信息
        /// </summary>
        /// <param name="packageGroup"></param>
        /// <returns></returns>
        public PackageItemInfo GetPackageGroupInstalledPackage(PackageGroupInfo packageGroup)
        {
            PackageGroupInfo groupInfo = GetPackageGroupInfoByIndex(packageGroup.packageGroupID, packageGroup.groupIndex);

            if (groupInfo == null) return null;

            return groupInfo.GetInstalledPackageInfo();
        }

        /// <summary>
        /// 获取包组中最新的包信息
        /// </summary>
        /// <param name="packageGroup"></param>
        /// <returns></returns>
        public PackageItemInfo GetPackageGroupLastPackage(PackageGroupInfo packageGroup)
        {
            PackageGroupInfo groupInfo = GetPackageGroupInfoByIndex(packageGroup.packageGroupID, packageGroup.groupIndex);

            if (groupInfo == null) return null;

            return groupInfo.GetLastPackageInfo();
        }

        /// <summary>
        /// 获取当前选中的包组中安装的包信息
        /// </summary>
        /// <returns></returns>
        public PackageItemInfo GetCurSelectedPackageGroupInstalledPackage()
        {
            PackageGroupInfo groupInfo = GetPackageGroupInfoByIndex(curSelectedGroupID, curSelectedGroupIndex);

            if (groupInfo == null) return null;

            return groupInfo.GetInstalledPackageInfo();
        }

        /// <summary>
        /// 获取当前选中的包组中最新的包信息
        /// </summary>
        /// <returns></returns>
        public PackageItemInfo GetCurSelectedPackageGroupLastPackage()
        {
            PackageGroupInfo groupInfo = GetPackageGroupInfoByIndex(curSelectedGroupID, curSelectedGroupIndex);

            if (groupInfo == null) return null;

            return groupInfo.GetLastPackageInfo();
        }
    }
}